package com.data.common.util;

import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/**
 * IP地址
 *
 * @Author boot
 * @email boot@163.com
 * @Date 2021年01月14日
 */
public class IPUtils {
    private static Logger logger = LoggerFactory.getLogger(IPUtils.class);

    private static final String UNKOWN_ADDRESS = "未知位置";

    /**
     * 获取IP地址
     * <p>
     * 使用Nginx等反向代理软件， 则不能通过request.getRemoteAddr()获取IP地址
     * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP地址，X-Forwarded-For中第一个非unknown的有效IP字符串，则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
                // 多次反向代理后会有多个ip值，第一个ip才是真实ip
                if (ip.indexOf(",") != -1) {
                    ip = ip.split(",")[0];
                }
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
            logger.error("IPUtils ERROR ", e);
        }

//        //使用代理，则获取第一个IP地址
//        if(StringUtils.isEmpty(ip) && ip.length() > 15) {
//			if(ip.indexOf(",") > 0) {
//				ip = ip.substring(0, ip.indexOf(","));
//			}
//		}

        return ip;
    }

    /**
     * 根据IP获取地址
     *
     * @param ip
     * @param algorithm 查询算法
     * @param path      db文件绝对位置
     * @return 国家|区域|省份|城市|ISP
     * @see DbSearcher
     * DbSearcher.BTREE_ALGORITHM; //B-tree
     * DbSearcher.BINARY_ALGORITHM //Binary
     * DbSearcher.MEMORY_ALGORITYM //Memory
     */
    @SneakyThrows
    public static String getAddress(String ip, int algorithm, String path) {
        if (!Util.isIpAddress(ip)) {
            logger.error("错误格式的ip地址: {}", ip);
            return UNKOWN_ADDRESS;
        }
        File file = new File(path);
        if (!file.exists()) {
            logger.error("地址库文件不存在");
            return UNKOWN_ADDRESS;
        }
        DbSearcher searcher = new DbSearcher(new DbConfig(), path);
        DataBlock dataBlock;
        switch (algorithm) {
            case DbSearcher.BTREE_ALGORITHM:
                dataBlock = searcher.btreeSearch(ip);
                break;
            case DbSearcher.BINARY_ALGORITHM:
                dataBlock = searcher.binarySearch(ip);
                break;
            case DbSearcher.MEMORY_ALGORITYM:
                dataBlock = searcher.memorySearch(ip);
                break;
            default:
                logger.error("未传入正确的查询算法");
                return UNKOWN_ADDRESS;
        }
        return dataBlock.getRegion();
    }

    public static AddressInfo getAddress(String ip) {
        String host = "https://searchip.market.alicloudapi.com";
        String path = "/aliyun/ip/search";
        String method = "GET";
        String appcode = "b7f42847ef2641eeabe6cef0150be1fc";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //需要给X-Ca-Nonce的值生成随机字符串，每次请求不能相同
        headers.put("X-Ca-Nonce", UUID.randomUUID().toString());
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("ip", ip);

        try {
            /**
             * 重要提示如下:
             * HttpUtils请从
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
             * 下载
             *
             * 相应的依赖请参照
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
             */
            HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
            //获取response的body
            String json = EntityUtils.toString(response.getEntity());
            AddressResult result = JSONObject.parseObject(json, AddressResult.class);
            if (result.getCode()==0){
                return result.getData();
            }
        } catch (Exception e) {
            logger.error("ip地址获取异常", e);
            return null;
        }
        return null;
    }

    public static void main(String[] args) {
        AddressInfo info = getAddress("182.48.110.215");
        System.out.println(JSONObject.toJSONString(info));
    }

    @Data
    public static class AddressResult{

        private int code;

        private String msg;

        private String traceId;

        private AddressInfo data;
    }

    @Data
    public static class AddressInfo {

        @ApiModelProperty(value = "地址")
        private String address;

        @ApiModelProperty(value = "ip类型")
        private String type;

        @ApiModelProperty(value = "国家")
        private String nation;

        @ApiModelProperty(value = "省份")
        private String province;

        @ApiModelProperty(value = "provinceCode")
        private String provinceCode;

        @ApiModelProperty(value = "城市")
        private String city;

        @ApiModelProperty(value = "cityCode")
        private String cityCode;

        @ApiModelProperty(value = "维度")
        private String lat;

        @ApiModelProperty(value = "经度")
        private String lng;

    }

}


